/*
不安全代码 unsafe
1. 裸指针 （*const T 和 *mut T）与引用（&T 和 &mut T）不同，它们不受 Rust 所有权系统和借用检查器的约束。



*/
use std::slice;
use std::{env::consts, sync::Mutex};
use std::{slice::from_raw_parts, str::from_utf8_unchecked};

///
/// 1.1 解引用裸指针
///
pub fn run1() {
    let mut num = 5;
    let mut str: &'static str = "1234";
    //创建裸指针是安全的 只有在使用他们的时候才需要 unsafe 包裹
    let r = &num as *const i32; //不可变的裸指针
    let r1 = &mut str as *mut &'static str; //可变的裸指针 字符串
    let r2 = &mut num as *mut i32; //可变的裸指针 数值类型

    // println!("r is: {}", *r); 编译器检查 不通过 不允许裸指针

    /*
     裸指针 可能会指向 一块 无效内存
     也可能 多个 可变指针指向同一个内存，导致 数据竞争
     不能保证 指针真实的生命周期 和指向的内存的数据的有效性 ，需要自己去把握

    */

    //基于内存地址创建裸指针
    /*
    这里基于一个内存地址来创建裸指针，可以想像，这种行为是相当危险的。
    试图使用任意的内存地址往往是一种未定义的行为(undefined behavior)，
    因为该内存地址有可能存在值，也有可能没有，就算有值，也大概率不是你需要的值
     */
    let address = 0x012345;
    let r3 = address as *const i32;

    //正确地使用内存地址

    unsafe {
        println!("r : {}", *r);
        println!("r1 : {}", *r1);

        *r1 = "今晚打老虎";
        println!("r1 : {}", *r1);

        println!("r2:{}", *r2);
        *r2 = 666;
        println!("r2:{}", *r2);
        println!("r3:{}", *r3);
    }
}

///
///2. 用 unsafe 修饰 函数 告诉编译器这是一个不安全的函数
///
///
pub unsafe fn run2() {
    run1();
}

static mut COUNTER: i32 = 666;
fn add_to_counter(inc: i32) {
    unsafe {
        COUNTER += inc;
    }
}

///3. 访问 或者修改静态配置
pub fn run3() {
    add_to_counter(6);
    unsafe {
        // println!("COUNTER: {}", COUNTER); // 读取也需要 unsafe
    }
}

/// 先给内存复制，然后再获取内存地址和长度
pub fn run4() {
    //获取字符串地 内存地址和长度
    fn get_momory_location() -> (usize, usize) {
        let str = "大王叫我来巡山";
        let pointer = str.as_ptr() as usize; //获取 内存地址 
        let len = str.len();
        (pointer, len)
    }

    fn get_str_at_location(pointer: usize, len: usize) -> &'static str {
        unsafe { from_utf8_unchecked(from_raw_parts(pointer as *const u8, len)) }
    }

    let (point, len) = get_momory_location();
    let msg = get_str_at_location(point, len);

    println!("The {} bytes at 0x{:X} stored: {}", len, point, msg);

    // 如果大家想知道为何处理裸指针需要 `unsafe`，可以试着反注释以下代码
    //let message = get_str_at_location(1000, 10);//从不知名地址 获取10 个字符串
    // println!("message {} ",message);
}

///使用 * 解引用
///
/// 将一个值隐式转换为裸指针或者 显式转换为 裸指针
pub fn run5() {
    let a = 666;
    let b = &a as *const i32; //显式转换为裸指针
    let c: *const i32 = &a; //隐式转换为裸指针

    let mut d = 111;
    let e = &mut d as *mut i32;

    unsafe {
        println!("b :{}", *b);
        println!("c :{}", *c);
        println!("e:{}", *e);
        *e = 1232344;
        println!("e:{}", *e);
    }
}

///基于智能指针创建裸指针
pub fn run6() {
    let a = Box::new(10);

    // 需要先解引用a  两个裸指针 指向同一个数据
    let b: *const i32 = &*a;
    // 使用 into_raw 来创建
    let c: *const i32 = Box::into_raw(a);

    unsafe {
        println!("b:{}", *b);
        println!("c:{}", *c);
    }
}


pub fn run7() {

    fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
        let len = slice.len();
        let ptr = slice.as_mut_ptr();//指向 slice 首地址的裸指针 *mut i32

        assert!(mid <= len);

        unsafe {
            (
                slice::from_raw_parts_mut(ptr, mid),//函数通过指针和长度来创建一个新的切片，简单来说，该切片的初始地址是 ptr，长度为 mid
                slice::from_raw_parts_mut(ptr.add(mid), len - mid),
            )
        }
    }

    let mut v = vec![1, 2, 3, 4, 5, 6];

    let r = &mut v[..];

    let (a, b) = split_at_mut(r, 3);

    assert_eq!(a, &mut [1, 2, 3]);
    assert_eq!(b, &mut [4, 5, 6]);

}

// 可能包含不安全代码 所以都要用  unsafe 包裹
unsafe extern "C"{
    unsafe fn abs(input:i32)->i32;
}

///FFI（Foreign Function Interface）可以用来与其它语言进行交互
pub fn run8(){
    unsafe {
         println!("Absolute value of -3 according to C: {}", abs(-3));
    }
}



pub fn run() {
    run8();
    //run7();
    //run6();
    //run5();
    // run4();
    //run3();

    //不安全的函数调用 也需要用 unsafe 包裹
    // unsafe {
    //     run2();
    // }

    //run1();
}
